import websocket
import json
import ssl
import time
import threading
from send_request import SendSessionRequest
from config import get_settings
from abc import abstractmethod
from cache import TTLCache

SETTINGS = get_settings()
POST_URL = SETTINGS.post_url
POST_OPEN = SETTINGS.post_open
WS_USERNAME = SETTINGS.user_name
WS_PASSWORD = SETTINGS.user_password
WS_URL = SETTINGS.ws_url
File_URL_PREFIX = SETTINGS.file_url_prefix

HEADER = {
    "Content-Type": "application/json; charset=UTF-8"
}
CACHE = TTLCache(max_size=5, ttl=60)

class ResMessage:
    def __init__(self, d):
        self.__dict__ = d


class Msg:
    def __init__(self, d):
        self.__dict__ = d


class DeviceInfo:
    deviceId = ""
    deviceName = ""
    action = ""
    deviceType = ""

    def __init__(self):
        pass

    def keys(self):
        '''当对实例化对象使用dict(obj)的时候, 会调用这个方法,这里定义了字典的键, 其对应的值将以obj['name']的形式取,
        但是对象是不可以以这种方式取值的, 为了支持这种取值, 可以为类增加一个方法'''
        return ('deviceId', 'deviceName', 'action', 'deviceType')

    def __getitem__(self, item):
        '''内置方法, 当使用obj['name']的形式的时候, 将调用这个方法, 这里返回的结果就是值'''
        return getattr(self, item)


class WebsocketBaseService(threading.Thread):
    def __init__(self, url):
        threading.Thread.__init__(self)
        #websocket.enableTrace(True)
        self.wsObj = websocket.WebSocketApp(url,
                                            on_open=self.on_open,
                                            on_message=self.on_message,
                                            on_error=self.on_error,
                                            on_close=self.on_close)

    @abstractmethod
    def on_open(self, ws):
        pass

    @abstractmethod
    def on_message(self, ws, message):
        pass

    def on_error(self, ws, error):
        print("发生错误:", error)

    def on_close(self, ws, code, msg):
        print("Closed")

    def run(self):
        self.wsObj.run_forever(sslopt={"cert_reqs": ssl.CERT_NONE})


class WebsocketService(WebsocketBaseService):
    def __init__(self, url):
        super().__init__(url)
        self.loginHandle = None
        self.clientid = None
        self.sendSessionRequest = SendSessionRequest()

    def on_message(self, ws, message):
        print('收到消息：%s' % message, end="")
        data = json.loads(message, object_hook=ResMessage)
        msg = json.loads(data.msg, object_hook=Msg)
        self.clientid = data.clientid
        method = msg.method
        if method == 'systemManager.onLogin':
            params = msg.params
            self.loginHandle = params.loginHandle

            # if not WebsocketServiceUploadFile.init_flag:
            #     ws_upload_file = WebsocketServiceUploadFile(WS_URL, params.loginHandle, data.clientid)
            #     ws_upload_file.start()

            keepLive = KeepLiveService(self, self.wsObj)
            if keepLive.is_alive():
                return
            keepLive.start()
        elif method == 'eventManager.notify':
            params = msg.params
            if params.code == 'DeviceStatus':
                statusData = {
                    "type": "deviceStatus",
                    "data": {
                        "deviceId": params.deviceId,
                        "action": params.action
                    }
                }
                print("推送设备状态到灯杆系统：%s" % json.dumps(statusData))
                self.send_data(statusData)
        elif method == 'configManager.onDeviceList':
            list = msg.params.list
            deviceList = []
            for device in list:
                deviceInfo = DeviceInfo()
                deviceInfo.deviceId = device.deviceId
                deviceInfo.deviceName = device.deviceName
                deviceInfo.deviceType = device.deviceType
                deviceList.append(deviceInfo)
            json_list = json.dumps([dict(item) for item in deviceList], ensure_ascii=False)
            sendData = {
                "type": "onDeviceList",
                "data": json_list
            }
            print("推送设备信息到灯杆平台：%s" % sendData)
            self.send_data(sendData)
        elif method == 'audioManager.onGetAudioFileList':
            files = msg.params.files
            fileList = []
            for file in files:
                fileList.append({
                    "id": file.id,
                    "name": file.name,
                    "seconds": file.seconds
                })
            sendData = {
                "type": "onGetAudioFileList",
                "data": fileList
            }
            print("推送文件信息到灯杆平台：%s" % sendData)
            self.send_data(sendData)
        elif method == 'audioManager.onGetBCTaskList':
            tasks = msg.params.tasks
            taskList = []
            for task in tasks:
                taskList.append({
                    "bcType": task.bcType,
                    "deviceIds": task.deviceIds,
                    "taskType": task.taskType,
                    "weekDays": task.weekDays,
                    "duration": {
                        "enable": task.duration.enable,
                        "seconds": task.duration.seconds
                    },
                    "loop": {
                        "enable": task.loop.enable,
                        "times": task.loop.times
                    },
                    "enable": task.enable,
                    "execMode": task.execMode,
                    "expire": {
                        "beginDate": task.expire.beginDate,
                        "enable": task.expire.enable,
                        "endDate": task.expire.endDate
                    },
                    "fileIds": task.fileIds,
                    "id": task.id,
                    "startTimeOfDay": task.startTimeOfDay,
                    "volume": task.volume,
                    "weekDays": task.weekDays
                })
            sendData = {
                "type": "onGetAudioFileList",
                "data": taskList
            }
            print("推送广播任务列表信息到灯杆平台：%s" % sendData)
            self.send_data(sendData)
        elif method == 'audioManager.onUploadAudioFile':
            #pass
            CACHE.set(msg.id, msg.id)

            # upload_file_url = CACHE.get(msg.id)
            # sendData = {
            #     "type": "onUploadAudioFile",
            #     "data": {
            #         "fileId": msg.params.fileId,
            #         "fileUrl": upload_file_url
            #     }
            # }
            #print("推送广播任务列表信息到灯杆平台：%s" % sendData)

    def on_open(self, ws):
        registor = '{"cmd":"register","msg":""}'
        ws.send(registor)
        params = {
            "userName": WS_USERNAME,
            "password": WS_PASSWORD
        }
        msg = {
            "method": "systemManager.login",
            "params": params
        }
        login = {
            "cmd": "send",
            "msg": json.dumps(msg)
        }
        print("登录信息：%s" % json.dumps(login))
        ws.send(json.dumps(login))

    def send_data(self, send_data):
        if POST_OPEN:
            self.sendSessionRequest.requests(url=POST_URL, method="post", json=send_data, headers=HEADER)
        else:
            print("推送关闭！")

    def on_run_forever(self):
        self.wsObj.run_forever(sslopt={"cert_reqs": ssl.CERT_NONE})

    def keep_live(self, ws):
        # 打印当前时间
        print(time.strftime('%Y-%m-%d %H:%M:%S'))
        params = {
            "loginHandle": self.loginHandle
        }
        msg = {
            "method": "systemManager.keepAlive",
            "params": params
        }
        keepAlive = {
            "cmd": "send",
            "clientid": self.clientid,
            "msg": json.dumps(msg)
        }
        # 每隔15秒执行一次
        ws.send(json.dumps(keepAlive))

    def run(self):
        self.wsObj.run_forever(sslopt={"cert_reqs": ssl.CERT_NONE})


class KeepLiveService(threading.Thread):
    instance = None
    init_flag = False

    def __new__(cls, *args, **kwargs):
        # 判断是否是空对象
        if (cls.instance is None):
            # 调用父类方法为对象分配空间
            cls.instance = super().__new__(cls)
        return cls.instance

    def __init__(self, ws, wsObj):
        if KeepLiveService.init_flag:
            return
        threading.Thread.__init__(self)
        self.ws = ws
        self.wsObj = wsObj
        KeepLiveService.init_flag = True

    def keep_live(self):
        while True:
            # print("Thread ID: ", threading.get_ident())
            # 打印当前时间
            # print( time.strftime('%Y-%m-%d %H:%M:%S'))
            params = {
                "loginHandle": self.ws.loginHandle
            }
            msg = {
                "method": "systemManager.keepAlive",
                "params": params
            }
            keepAlive = {
                "cmd": "send",
                "clientid": self.ws.clientid,
                "msg": json.dumps(msg)
            }
            self.wsObj.send(json.dumps(keepAlive))
            time.sleep(15)

    def run(self):
        self.keep_live()


class WebsocketServiceUploadFile(WebsocketBaseService):
    # instance = None
    # init_flag = False
    # def __new__(cls, *args, **kwargs):
    #     if (cls.instance is None):
    #         cls.instance = super().__new__(cls)
    #     return cls.instance
    def __init__(self, url, loginHandle, clientid):
        # if WebsocketServiceUploadFile.init_flag:
        #     return
        super().__init__(url)
        self.loginHandle = loginHandle
        self.clientid = clientid
        self.open_flag = False
        # WebsocketServiceUploadFile.init_flag = True

    def on_message(self, ws, message):
        print('收到UploadFile消息：%s' % message, end="")

    def on_open(self, ws):
        print("UploadFile Opened!")
        registor = {
            "cmd": "register",
            "clientid": self.clientid,
            "loginHandle": self.loginHandle,
            "sessiontype": "mt16",
            "deviceid": 1,
            "msg": ""
        }
        ws.send(json.dumps(registor))
        self.open_flag = True